SQL 查询需要花费一定时间,有时会长得让人心烦。
为了尽可能缩短查询时间,提高效率,带来良好的用户体验,我们可以:
- 使用索引
- 升级硬件
- 挑选合适的数据类型
- 检查 MySQL 的查询优化程序
- 编写更好的查询 SQL 以影响服务器的调度机制
使用索引
用来加快查询的技术有很多,其中最重要的是索引。通常,能够造成查询速度最大差异的是索引的正确使用。很多时候,当查询速度很慢时,添加上索引后就能迅速解决问题。但情况也不总是这样,因为优化并不总是一件简单的事情。然而,在许多情况下,假如你不使用索引,那么试图通过其他途径来提高性能则纯粹是浪费时间。你应该首先使用索引来最大程度地改进性能,然后再看是否还有其他技术可以采用。
对索引的研究请参考 MySQL 数据库优化之索引。
升级硬件
利用较好的硬件可使服务器运行得更快。
通过硬件优化,最重要的原则与调整服务器参数时的原则一样——将尽可能多的信息快速储存起来,并且尽可能久地保存它们。
对硬件配置的以下几个方面进行修改来改进服务器性能:
- 在机器里安装更多的内存。这会增加服务器的缓存和缓冲区的容量,从而允许数据在内存中能够保持更长的时间,较少需要从磁盘上获取信息。
- 如果你有足够的RAM可以让所有的数据交换都发生一个内存文件系统里,可以重新配置你的系统来删除所有的磁盘数据交换设备。要知道,即使你有足够的RAM,有些系统仍会与磁盘交换数据。
- 添加更快的磁盘来改善 I/O 等待时间。在这里,寻道时间通常是性能的主要决定因素。侧向移动磁头是比较慢的。当磁头位置确定以后,把信息从磁道上读出来相对要快一些。不过,要是你能在更多的内存和更快的磁盘之间做选择,应选更多的内存。内存永远比磁盘快,添加内存后可以使用较大的缓存并减少磁盘的活动量。
- 使用多处理器硬件。对于 MySQL 服务器这样的多线程程序来说,多处理器硬件可以同时执行多个线程
- (读写分离)在物理设备之间分散磁盘读写活动,提高并行度。通过多个物理设备将读和写分开,比在一个设备上读和写要快。例如,假设将数据库存储在一个设备上,将日志文件存储在另外一个设备上,那么对两个设备同时写入就要比数据库和日志文件都在同一个设备上时快一些。注意,在同一个物理设备上采用不同分区是没有用的,不能算并行,因为它们还是要竞争同一个物理资源(磁头)。
简而言之,加内存!换磁盘!升 CPU!搞机器!即,打钱!!!
挑选合适的数据类型
不同的数据类型也会影响查询的性能,因此:
- 尽量使用数值操作而少使用字符串操作,因为前者通常运算更快
- 若“小”类型够用,就不要选“大”类型,因为前者处理速度更快
- 若可选择数据行的存储格式,尽量选择最适合你的存储引擎格式
- 尽量把数据列声明为
NOT NULL - 考虑使用
ENUM数据列 - 利用
PROCEDURE ANALYSE()语句分析数据表,其可以提供声明建议
检查 MySQL 的查询优化程序
在 MySQL ,我们可以通过命令来查看相关 SQL 的执行情况以决定如何优化 SQL 的执行效率,具体请参考 MySQL 数据库优化之分析执行计划
合适的 SQL 优化
ORDER BY 优化
- 根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则。
- 尽量使用覆盖索引。
- 多字段排序,一个升序一个降序,此时需要注意联合索引在创建时的规则(ASC/DESC)。
- 如果不可避免的出现filesort,大数据量排序时,可以适当增大排序缓冲区大小sort_buffer_size(默认256k)。
GROUP BY 优化
- 在分组操作时,可以通过索引来提高效率
- 分组操作时,索引的使用也是满足最左前缀法则的
LIMIT 优化
一个常见又非常头疼的问题就是limit2000000,10,此时需要MySQL排序前2000010记录,仅仅返回2000000-2000010的记录,其他记录丢弃,查询排序的代价非常大。
LIMIT 走主键索引,过滤出小数据量,在多表联查
COUNT 优化
count的几种用法如下:
count(主键):InnoDB 引擎会遍历整张表,把每一行的主键id 值都取出来,返回给服务层。服务层拿到主键后,直接按行进行累加(主键不可能为 NULL)count(字段):- 有
NOT NULL约束:InnoDB 引擎会遍历整张表把每一行的字段值都取出来,返回给服务层,直接按行进行累加 - 无
NOT NULL约束:InnoDB 引擎会遍历整张表把每一行的字段值都取出来,返回给服务层,服务层判断是否为 NULL,不为 NULL,计数累加
- 有
count(1):InnoDB引擎遍历整张表,但不取值。服务层对于返回的每一行,放一个数字“1”进去,直接按行进行累加count (*):InnoDB引擎并不会把全部字段取出来,而是专门做了优化,不取值,服务层直接按行进行累加
按照效率排序的话,count (*) ≈ count(1) > count(主键) > count(字段),所以尽量使用count (*)。
参考
- Paul DuBois. MySQL 技术内幕 [M]. 人民邮电出版社, 2011